#include "world.h"

#include "camera.h"
#include "cloud.h"
#include "DirectXAudio.h"
#include "gui.h"
#include "player.h"
#include "radar.h"
#include "snowman.h"
#include "terrain.h"
#include "hat.h"
#include "helicopter.h"


CWorld::CWorld()
{
}

CWorld::~CWorld()
{
	delete gui;
	delete terrain;
	delete radar;
	terrain = NULL;
	gui = NULL;

	audioSystem = NULL;
}

CWorld::CWorld(CCamera *c)
{
	camera = c;
	terrain = new CTerrain(64, 1.0f);
	player = new CPlayer;
	audioSystem = new CDirectXAudio;
	gui = new CGUI;
	gameDone = false;
	radar = new CRadar;
	player->AttachTo(terrain);
	player->SetCamera(camera);
	player->SetTerrain(terrain);
	
	audioSystem->PlaySoundDX(audioSystem->iBackgroundMusic);
	//audioSystem->PlaySoundDX(audioSystem->iAmbient); // can't have both ambient and background playing

	player->SetAudioSystem(audioSystem);
	LoadWorld();
	timeStart = 300.0;			// 300 seconds = 5 minutes
	timeElapsed = 0.0;
	gui->SetCurrentTime(timeStart);
	gui->SetEnemiesLeft(numSnowmen);

	hatsCollected = 0;
	gui->setHatsCollected(hatsCollected);
}

void CWorld::Animate(float deltaTime)
{
	if(!gameDone) {
		timeElapsed += deltaTime;
		player->DoAnimate(deltaTime);
	}

	// set camera height based on player position on terrain
	camera->position.y = terrain->GetHeight(camera->position.x, camera->position.z) + player->size;	
	
	if (camera->position.x <= terrain->GetScanDepth())
		camera->position.x = terrain->GetScanDepth();
	if (camera->position.x >= terrain->GetWidth()*terrain->GetMul() - terrain->GetScanDepth())
		camera->position.x = terrain->GetWidth()*terrain->GetMul() - terrain->GetScanDepth();
	if (camera->position.z <= terrain->GetScanDepth())
		camera->position.z = terrain->GetScanDepth();
	if (camera->position.z >= terrain->GetWidth()*terrain->GetMul() - terrain->GetScanDepth())
		camera->position.z = terrain->GetWidth()*terrain->GetMul() - terrain->GetScanDepth();

	terrain->Animate(deltaTime);	// animate terrain
	const type_info &snowman = typeid(CSnowman);	// get snowmen typeid
	
	numSnowmen = CountObjectTypes(snowman);			// count snowmen

	gui->SetEnemiesLeft(numSnowmen);

	gui->SetCurrentTime(timeElapsed);
	hatsCollected = Hat::getHatsCollected();
	gui->setHatsCollected(hatsCollected);

}

void CWorld::FadeScreen()
{
	glPushMatrix();
	glLoadIdentity();
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_TEXTURE_2D);
	glColor4f(0.0f, 0.0f, 0.0f, 0.7f);
	glBegin(GL_QUADS);
	glVertex3f(-5, -5, -3.0);
	glVertex3f(5, -5, -3.0);
	glVertex3f(5, 5, -3.0);
	glVertex3f(-5, 5, -3.0);
	glEnd();
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
	glPopMatrix();
}

void CWorld::SetScreen(int width, int height)
{
	screenWidth = width;
	screenHeight = height;
}

void CWorld::Draw(CCamera *camera)
{
	terrain->Draw(camera);
	gui->Draw();

	if (gameDone)
	{
		FadeScreen();
		if (!player->isDead)
			gui->DrawWinner(hatsCollected);
		else
			gui->DrawLoser();
	}
}


//	Art Ordonez	--> Used to change View Matrix to 2D to display Radar Object, then change back to 3D for 3D object display
//(credit to Elgoog (stackoverflow.com) and Stephen for finding it)

void CWorld::Draw2D(int windowWidth, int windowHeight)
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(0.0, windowWidth, windowHeight, 0.0, -1.0, 10.0);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	glDisable(GL_CULL_FACE);
	glClear(GL_DEPTH_BUFFER_BIT);
	glDisable(GL_TEXTURE_2D);

	radar->Draw(windowHeight, terrain, &player->position, &camera->yaw);

	//More accurate crosshair! -SR
	glColor3f(1.0f, 0.0f, 0.0f);
	glBegin(GL_LINES);
		glVertex2f((float)(windowWidth/2) - 10, (float)(windowHeight/2));
		glVertex2f((float)(windowWidth/2) + 10, (float)(windowHeight/2));
	glEnd();
	glBegin(GL_LINES);
		glVertex2f((float)(windowWidth/2), (float)(windowHeight/2) - 10);
		glVertex2f((float)(windowWidth/2), (float)(windowHeight/2) + 10);
	glEnd();

	glEnable(GL_TEXTURE_2D);
	// Making sure we can render 3d again
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
}


void CWorld::OnPrepare()
{
	glClearColor(terrain->fogColor[0], terrain->fogColor[1], terrain->fogColor[2], terrain->fogColor[3]);
	terrain->Prepare();
	
	if ((numSnowmen <= 0) || (timeElapsed >= timeStart) || player->isDead)
		gameDone = true;
	
}


// LoadWorld()
// desc: initializes the world
void CWorld::LoadWorld()
{
	int enemyIdx = 0;
	int rndInt = 0;

	numSnowmen = 0;

	srand((unsigned int)time(NULL));
	
	rndInt = (rand() % (MAX_ENEMIES-4)) + 4;	// random # from 4 to MAX
	numSnowmen = rndInt;

	// generate snowmen
	for (enemyIdx = 0; enemyIdx < 50; enemyIdx++)
	{
		snowmenEnemy = new CSnowman;
		snowmenEnemy->AttachTo(terrain);
		snowmenEnemy->SetPlayer(player);
		snowmenEnemy->SetAudioSystem(audioSystem);
		snowmenEnemy->position.x = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
		snowmenEnemy->position.y = 0.0f;
		snowmenEnemy->position.z = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
	}

	// Generate helicopters
	heli = new Helicopter;
	heli->AttachTo(terrain);
	heli->SetAudioSystem(audioSystem);
	heli->player = player;
	heli->position.x = 300.0f;
	heli->position.y = 0.0f;
	heli->position.z = 300.0f;

	// Generate clouds
	// These have to be generated after solid objects, otherwise they will be drawn 
	// behind solid objects that are generated after them, even if the clouds are in
	// front of the solid objects.
	for (int i = 0; i < 40; i++)
	{
		CCloud* cloud = new CCloud;
		cloud->pitch = camera->pitch;
		cloud->position.x = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
		cloud->position.y = 0.0f;
		cloud->position.z = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
		cloud->forward = camera->lookAt.UnitVector();
		cloud->AttachTo(terrain);
	}
}

// CountObjectTypes
// desc: counts the number of objects passed as classID in the hierarchy
int CWorld::CountObjectTypes(const type_info &classID)
{
	int count = 0;
	CObject *c1;
	CObject *c2;

	c1 = (CObject*)terrain->childNode;

	while (c1 != NULL)
	{
		c2 = c1;
		do
		{
			if (typeid(*c2) == classID)
				count++;
			c2 = (CObject*)c2->nextNode;
		} while (!c2->IsFirstChild());

		c1 = (CObject*)c1->childNode;
	}

	return count;
}

